﻿// Learn more about F# at http://fsharp.net
namespace DotNetTracer
open System.Windows.Forms

module UIExt = 
    let makeWizardControl (parts: IWizardPart[]) = 
        let cntrl = new WizardControl()
        let idx = ref 0
        let data = Array.init (parts.Length) (fun _ -> None)

        let loadControl(i: int) (value: obj) = 
            cntrl.panel.Controls.Clear()
            let nestedCntrl = parts.[i].GetControl()
            nestedCntrl.Dock <- DockStyle.Fill
            
            cntrl.panel.Controls.Add(nestedCntrl)
            cntrl.btnPrevious.Enabled <- (i > 0)
            cntrl.btnNext.Enabled <- (i < parts.Length - 1)

        let startOver () = 
            idx := 0
            loadControl (!idx) None
        cntrl.btnStartOver.Click.Add(fun args -> startOver())
        
        cntrl.btnNext.Click.Add(fun args ->
            let ok,value = parts.[!idx].TryGetData()
            if ok then
                data.[!idx] <- Some value
                idx := !idx + 1
                loadControl (!idx) value)

        cntrl.btnPrevious.Click.Add(fun args ->
            idx := !idx - 1
            loadControl (!idx) data.[!idx])
        startOver()
        cntrl

module Entry = 
    let makeWizardPart<'T when 'T :> IWizardPart and 'T:(new: unit->'T)> () = 
        (new 'T()) :> IWizardPart

    let makeMainForm () = 
        let mainFrm = new MainForm()
        let inputFileCntrl = makeWizardPart<FileInputControl>()
        let typeInfoCntrl = makeWizardPart<TypeInfoControl>()
        let wizardCntrl = UIExt.makeWizardControl([|inputFileCntrl;typeInfoCntrl|])
        wizardCntrl.Dock <- DockStyle.Fill
        mainFrm.Controls.Add(wizardCntrl)
        mainFrm :> Form
    
    [<EntryPoint>]
    [<System.STAThread()>]           
    let main args =
//        let mainFrm = makeMainForm ()
//        mainFrm.ShowDialog() |> ignore
//        let inputPath = @"D:\NewProfiler\Cecil\jbevain-cecil-06279d0\TestApp\bin\Debug\TestApp.exe"
//        let libPath0 = @"D:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\2.0\Runtime\v4.0\FSharp.Core.dll"
//        AssemblyResolution.getAllAssemblies inputPath 
//        |> Seq.iter (printfn "%s")
        let instrumentFile () = 
            let di = System.IO.DirectoryInfo(@"D:\DotNetTracerTmp\")
            di.GetFiles()
            |> Seq.iter(fun fi -> System.IO.File.Delete(fi.FullName))
        
            Instrumentor.instrumentRecursively
                         @"D:\DotNetTracer\DotNetTracer\TestProject\bin\Debug\TestProject.exe"
                         @"D:\DotNetTracerTmp\"
                         (fun _ -> failwith "prompt does not work"
                                   false)

        let copyCallTree (info: MyInstrumentation.LogInfo.FuncInfo) 
                         (tree: MyInstrumentation.LogInfo.CallTree) = 
            MyInstrumentation.LogInfo.copyCallTree tree
                               (fun record children ->
                                      let funcName = info.[record.funcId].fullName
                                      let node =System.Windows.Forms.TreeNode(funcName, children)
                                      node.Tag <- (record.paramValues, record.returnValue)
                                      node
                               )

        let showTrace () =
            let records = MyInstrumentation.LogInfo.recordsFromFile(@"D:\DotNetTracerTmp\records.bin")
            //records |> Seq.iter(fun x -> printfn "%d - %s" x.logId x.shortName)  
            let d = System.Collections.Generic.Dictionary<int, MyInstrumentation.LogInfo.Record>()
            for r in records do
                //printfn "%d %s" r.logId r.fullName
                d.Add(r.logId, r)

            let calls = MyInstrumentation.LogInfo.readCalls d @"D:\DotNetTracerTmp\buffer_1"
            printfn "\n\n\n--------------------"
            //MyInstrumentation.LogInfo.dumpCallTree d calls
            let treeNode = copyCallTree d calls
            let mainFrm = new MainForm()
            mainFrm.callTree.Nodes.Add(treeNode)
            mainFrm.callTree.AfterSelect.Add(fun args ->
                            let lstBox = mainFrm.arguments
                            lstBox.Items.Clear()
                            let (parameters,ret) = unbox<string[]*string> args.Node.Tag
                            parameters |> Seq.iter(fun p -> lstBox.Items.Add(p)|> ignore)
                            lstBox.Items.Add("Returns:")
                            lstBox.Items.Add(ret) |> ignore
                    )
            treeNode.ExpandAll()
            mainFrm.ShowDialog()
//            MyInstrumentation.LogInfo.dumpCalls @"D:\DotNetTracerTmp\buffer_1"
            ()   
        showTrace ()
        //instrumentFile ()
        0
//to do:
//1. improve the format of the data, to make it more compact, e.g. handling of integers, handling of null and void
//              (before making an instrumented call, write the location
//                  e.g.
//                      main(...)//write args
//                          call, write (-1), -1,-2, etc. will be for locations (should be optional)
//                                  initially, can use stack trace to see how useful it is
//                  write 
//2. test with other library, namely C# libraries
//3. improve the presentation, e.g.
//          x = call(value1,value2)
//          y = call(x, ...)
//4. connect with source code and take variable names if possible
//          (break the code into loops and mark loops)
//5. check the left to do's and fixe them